package com.tcoding.client.privilege.user;

import com.jfoenix.controls.*;
import com.jfoenix.controls.cells.editors.TextFieldEditorBuilder;
import com.jfoenix.controls.cells.editors.base.GenericEditableTreeTableCell;
import com.jfoenix.controls.datamodels.treetable.RecursiveTreeObject;
import com.tcoding.client.model.UserDataModel;
import com.tcoding.client.privilege.user.vo.UserPhoenixVO;
import com.tcoding.client.request.Request;
import com.tcoding.client.request.feign.admin.UserFeign;
import com.tcoding.core.entity.User;
import com.tcoding.core.util.DateUtils;
import io.datafx.controller.ViewController;
import io.datafx.controller.flow.action.ActionMethod;
import io.datafx.core.concurrent.ProcessChain;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.control.TreeTableColumn.CellEditEvent;
import javafx.scene.layout.HBox;
import javafx.util.Callback;
import org.kordamp.ikonli.javafx.FontIcon;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

@ViewController(value = "/fxml/ui/TreeTableView.fxml", title = "Material Design Example")
public class UserManagementPhonixController {



    @FXML
    private JFXTreeTableView<UserPhoenixVO> editableTreeTableView;
    @FXML
    private JFXTreeTableColumn<UserPhoenixVO, String> userNameColumn;
    @FXML
    private JFXTreeTableColumn<UserPhoenixVO, String> accountColumn;
    @FXML
    private JFXTreeTableColumn<UserPhoenixVO, String> remarkColumn;
    @FXML
    private JFXTreeTableColumn<UserPhoenixVO, String> lastUpdateTimeColumn;
    @FXML
    private JFXTreeTableColumn<UserPhoenixVO, String> lastUpdatedByColumn;
    @FXML
    private JFXTreeTableColumn<UserPhoenixVO, String> operateColumn;
    @FXML
    private JFXTextField searchField;

    @Inject
    private UserDataModel dataModel;

    @FXML
    private Pagination pagination;

    /**
     * init fxml when loaded.
     */
    @PostConstruct
    public void init() {
        setupEditableTableView();
        pagination.pageCountProperty().bind(dataModel.pageCountProperty());
        pagination.setPageFactory(new Callback<Integer, Node>() {
            @Override
            public Node call(Integer param) {
                showPage(param + 1);
                return editableTreeTableView;
            }
        });
    }

    private <T> void setupCellValueFactory(JFXTreeTableColumn<UserPhoenixVO, T> column, Function<UserPhoenixVO, ObservableValue<T>> mapper) {
        column.setCellValueFactory((TreeTableColumn.CellDataFeatures<UserPhoenixVO, T> param) -> {
            if (column.validateValue(param)) {
                return mapper.apply(param.getValue().getValue());
            } else {
                return column.getComputedValue(param);
            }
        });
    }

    private void setupEditableTableView() {
        setupCellValueFactory(userNameColumn, UserPhoenixVO::nameProperty);
        setupCellValueFactory(accountColumn, UserPhoenixVO::userNameProperty);
        setupCellValueFactory(remarkColumn, UserPhoenixVO::descriptionProperty);
        setupCellValueFactory(lastUpdatedByColumn, UserPhoenixVO::updUserProperty);
        setupCellValueFactory(lastUpdateTimeColumn, UserPhoenixVO::updTimeProperty);

        Callback<TreeTableColumn<UserPhoenixVO, String>, TreeTableCell<UserPhoenixVO, String>> cellFactory = new Callback<TreeTableColumn<UserPhoenixVO, String>, TreeTableCell<UserPhoenixVO, String>>() {
            @Override
            public TreeTableCell<UserPhoenixVO, String> call(TreeTableColumn param) {

                final TreeTableCell<UserPhoenixVO, String> cell = new TreeTableCell<UserPhoenixVO, String>() {

                    private final ToggleButton resetBut = new ToggleButton();
                    private final ToggleButton editBut = new ToggleButton();
                    private final ToggleButton delBut = new ToggleButton();

                    {


                        resetBut.setTooltip(new Tooltip("重置密码"));
                        resetBut.getStyleClass().add("left-pill");
                        editBut.getStyleClass().add("center-pill");
                        delBut.getStyleClass().add("right-pill");

                        try {
                            editBut.setGraphic(new FontIcon("fas-pencil-alt"));
                            resetBut.setGraphic(new FontIcon("fas-recycle"));
                            delBut.setGraphic(new FontIcon("fas-trash-alt"));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }

//                        editBut.setOnMouseClicked(event -> {
//
//                            tableView.getSelectionModel().select(getIndex());
////                                actionHandler.navigate(UserEditController.class);
//                        });
//                        delBut.setOnMouseClicked(event -> {
//                            tableView.getSelectionModel().select(getIndex());
//                            delete();
//                        });
//                        resetBut.setOnMouseClicked(event -> {
//                            tableView.getSelectionModel().select(getIndex());
//                            restPassword();
//                        });
                    }

                    @Override
                    protected void updateItem(String item, boolean empty) {
                        super.updateItem(item, empty);
                        if (empty) {
                            setGraphic(null);
                        } else {
                            HBox hBox = new HBox(resetBut, editBut, delBut);
                            hBox.setSpacing(0);
                            hBox.setAlignment(Pos.CENTER);
                            setGraphic(hBox);
                        }
                    }
                };
                return cell;
            }
        };


        operateColumn.setCellFactory(cellFactory);

        // add editors
        userNameColumn.setCellFactory((TreeTableColumn<UserPhoenixVO, String> param) -> {
            return new GenericEditableTreeTableCell<>(
                    new TextFieldEditorBuilder());
        });
        userNameColumn.setOnEditCommit((CellEditEvent<UserPhoenixVO, String> t) -> {
            t.getTreeTableView()
                    .getTreeItem(t.getTreeTablePosition()
                            .getRow())
                    .getValue().userNameProperty().set(t.getNewValue());
        });
        // add editors
        accountColumn.setCellFactory((TreeTableColumn<UserPhoenixVO, String> param) -> {
            return new GenericEditableTreeTableCell<>(
                    new TextFieldEditorBuilder());
        });
        accountColumn.setOnEditCommit((CellEditEvent<UserPhoenixVO, String> t) -> {
            t.getTreeTableView()
                    .getTreeItem(t.getTreeTablePosition()
                            .getRow())
                    .getValue().userNameProperty().set(t.getNewValue());
        });


        final ObservableList<UserPhoenixVO> dummyData = dataModel.getObservableUsers();
        editableTreeTableView.setRoot(new RecursiveTreeItem<>(dummyData, RecursiveTreeObject::getChildren));
        editableTreeTableView.setShowRoot(false);
        editableTreeTableView.setEditable(true);

        searchField.textProperty()
                .addListener(setupSearchField(editableTreeTableView));
    }

    private ChangeListener<String> setupSearchField(final JFXTreeTableView<UserPhoenixVO> tableView) {
        return (o, oldVal, newVal) ->
                tableView.setPredicate(personProp -> {
                    final UserPhoenixVO person = personProp.getValue();
                    return person.nameProperty().get().contains(newVal)
                            || person.userNameProperty().get().contains(newVal);

                });
    }


    private void showPage(Integer page) {
        Map<String, Object> queryMap = new HashMap<>();
        queryMap.put("keyId", searchField.getText());
        queryMap.put("page", page);
        query(queryMap);

    }

    @ActionMethod("search")
    private void search() {
        pagination.currentPageIndexProperty().setValue(0);

        Map<String, Object> queryMap = new HashMap<>();
        queryMap.put("keyId", searchField.getText());
        query(queryMap);

    }

    private void query(Map<String, Object> queryMap) {
        System.out.println("加载数据............");
        ProcessChain.create()
                .addRunnableInPlatformThread(() -> {
//                    spinnerPane.setVisible(true);
//                    centPane.setDisable(true);
                })
                .addSupplierInExecutor(() -> Request.connector(UserFeign.class).getPageList(queryMap)
                )
                .addConsumerInPlatformThread(result -> {
//                    dataModel.getUsers().clear();
                    dataModel.getObservableUsers().clear();
                    List<User> userList = result.getDatas();
                    dataModel.setPageCount((int) result.getTotal());
                    for (User user : userList) {
//                        dataModel.getUsers().add(new UserVO(user.getId(), user.getName(), user.getUsername(), DateUtils.formatDate(user.getUpdTime(), DateUtils.DATETIME_FORMAT), user.getUpdUser(), user.getSex(), user.getDescription()));
                        dataModel.getObservableUsers().add(new UserPhoenixVO(user.getId(), user.getName(), user.getUsername(), DateUtils.formatDate(user.getUpdTime(), DateUtils.DATETIME_FORMAT), user.getUpdUser(), user.getSex(), user.getDescription()));
                    }
                })
                .withFinal(() -> {
//                    spinnerPane.setVisible(false);
//                    centPane.setDisable(false);
                })
                .onException(e -> e.printStackTrace())
                .run();
    }
}
